#include "GraphicsManager.h"

//Include our GeometryGenerator - creates our full
//screen quad (for use in demoing portions of the system). 
#include "GeometryGenerator.h"

//For the rendering stage (stage 3), we need to modify the depth
//test - the depth stencil state will be created here.
#include "RenderStates.h"

//Complete the forward declaration.
#include "Application.h"
#include "ShaderManager.h"
#include "VirtualCamera.h"

//Full screen quad effect
#include "TexturedFullScreenQuadFX.h"
//Our Light Culling effect
#include "TileForwardLightCullCSFX.h" 
//Our light rendering effect
#include "DebugDrawLightsFX.h"

//Init static data
GraphicsManager* GraphicsManager::instance = 0;

//
//General Engine Functions - Eg, the inits, release, OnResize etc.
//

GraphicsManager::GraphicsManager()
	: sharedShaderManager(0), //Init shared shader manager pointer to NULL. 
	  d3dDriverType(D3D_DRIVER_TYPE_HARDWARE), //Default driver type is hardware
	  d3dDevice(0),
	  d3dImmediateContext(0),
	  swapChain(0),
	  backBufferRenderTargetView(0),
	  depthStencilView(0),
	  depthStencilSRV(0),

	  //Initially disabled.
	  msaaEnabled(false),
	  msaaQuality(0),

	  quadVB(0),
	  quadIB(0),
	  pointVB(0),
	  lightsInstancedBuffer(0),

	  //Light culling data
	  lightListBuffer(0),
	  lightListIndexBuffer(0),
	  lightListStartEndBuffer(0),
	  lightListBufferSRV(0),
	  lightListIndexBufferUAV(0),
	  lightListStartEndBufferUAV(0),
	  lightListIndexBufferSRV(0),
	  lightListStartEndBufferSRV(0),
	  maxTileZBuffer(0),
	  maxTileZBufferUAV(0),

	  //Init buffer views to NULL.
	  lightListIndexBufferTSRV(0), 
	  lightListIndexBufferTUAV(0), 
	  lightListStartEndBufferTSRV(0), 
	  lightListStartEndBufferTUAV(0),

	  lightCount(0)
{}

GraphicsManager::~GraphicsManager()
{
	ReleaseCOM(backBufferRenderTargetView);
	ReleaseCOM(depthStencilView);
	ReleaseCOM(depthStencilSRV);
	ReleaseCOM(swapChain);

	// Restore all default settings.
	if( d3dImmediateContext )
		d3dImmediateContext->ClearState();

	ReleaseCOM(d3dImmediateContext);
	ReleaseCOM(d3dDevice);

	//Delete buffers
	ReleaseCOM(quadVB);
	ReleaseCOM(quadIB);
	ReleaseCOM(pointVB);
	ReleaseCOM(lightsInstancedBuffer);

	//Light culling data
	ReleaseCOM(lightListBuffer);
	ReleaseCOM(lightListIndexBuffer);
	ReleaseCOM(lightListStartEndBuffer);
	ReleaseCOM(lightListBufferSRV);
	ReleaseCOM(lightListIndexBufferUAV);
	ReleaseCOM(lightListStartEndBufferUAV);
	ReleaseCOM(lightListIndexBufferSRV);
	ReleaseCOM(lightListStartEndBufferSRV);
	ReleaseCOM(maxTileZBuffer);
	ReleaseCOM(maxTileZBufferUAV);

	//Release T views - note that we do NOT store the buffers (Release them 
	//once the views have been created) because we do not need to. 
	ReleaseCOM(lightListIndexBufferTSRV);
	ReleaseCOM(lightListIndexBufferTUAV);
	ReleaseCOM(lightListStartEndBufferTSRV);
	ReleaseCOM(lightListStartEndBufferTUAV);
}

GraphicsManager* GraphicsManager::GetInstance()
{
	if (!instance)
		instance = new GraphicsManager();

	return instance;
}

void GraphicsManager::Release()
{
	//Release render states
	RenderStates::DestroyAll();

	//Release Shader Manager
	if (sharedShaderManager)
	{
		sharedShaderManager->Release();
		sharedShaderManager = NULL;
	}

	if (instance)
	{
		delete instance;
		instance = NULL;
	}
}

void GraphicsManager::Init(HWND mainWnd)
{
	//static (function scope that retains its value after the function
	//returns) bool indicating if we have (or have not) initilized the graphics
	//manager. It would probably be a nightmare if a programmer decided
	//to init this class multiple times (D3D memory leakes being the top irratance - 
	//in preperation for Games Case, I REALLY dont want to be trying to work
	//out WTF has happened.)
	static bool init = false;

	if (!init)
	{
		//Grab reference to shared application.
		sharedApplication = Application::GetInstance();

		//Init D3D
		InitDirect3D(mainWnd);

		//Init Render States
		RenderStates::InitAll(d3dDevice);

		//Init shader manager.
		sharedShaderManager = ShaderManager::GetInstance();
		//Call the OnResize() now - this will tell each effect what the render
		//dimensions initially are.
		sharedShaderManager->OnResize(backBufferWidth, backBufferHeight);

		//Grab references to effects.
		//Used to render full screen quads textured - eg, rendering out the
		//depth buffer.
		quadEffect = sharedShaderManager->ReturnTexturedFullScreenQuadFX();
		//Used to preform the tile culling stage of our renderer. (Private
		//to the GraphicsManager - ie, can not be accessed from other classes (unless
		//you make a friend declaration, of course...)
		tileCullCSEffect = sharedShaderManager->ReturnTileForwardLightCullCSFX();
		//Used to render the lights
		lightsDrawEffect = sharedShaderManager->ReturnDebugDrawLightsFX();

		//Create debug quad.
		CreateFullScreenQuad();
		//Create sphere
		CreateLightPointVertexBuffer();

		//Set init to true to avoid damages if a programmer decides
		//to Init the graphics manager more than once.
		init = true;
	}
}

void GraphicsManager::InitDirect3D(HWND mainWnd)
{
	//If debug mode, set the D3D11_CREATE_DEVICE_DEBUG flag
	UINT createDeviceFlags = 0;
#if defined (DEBUG) || defined (_DEBUG)
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	//Feature levels struct to be passed to D3D11CreateDevice()
	D3D_FEATURE_LEVEL featureLevel;

	//Create the device. 
	HRESULT hr = D3D11CreateDevice(
		NULL,                 //Default adaptor
		d3dDriverType,
		NULL,
		createDeviceFlags,
		NULL, NULL,            //Default feature levels array
		D3D11_SDK_VERSION,
		&d3dDevice,
		&featureLevel, 
		&d3dImmediateContext);

	//Check for errors when creating the device. 
	if (FAILED(hr))
	{
		MessageBox(0,L"D3D11CreateDevice Failed",0,0);
		exit(3);
	}
	
	if (featureLevel != D3D_FEATURE_LEVEL_11_0)
	{
		MessageBox(0, L"Direct3D feature 11 not supported, creating software driver (TYPE_REFERENCE)"
			          L"This is *very* slow - I suggest resizing the window to the minimum for some performance", 
					  0, 0);
		//***FOR UNI***
		//The Pc's in the games lab dont have a D3D11 supported GPU
		//so we will create a driver in software (D3D_DRIVER_TYPE_REFERENCE)
		//Everything* in my application should work happily after this
		//allthough, MUCH slower (expect single figure FPS). At least it
		//kind of works...
		//
		//*(Probably not....)

		//Release the device and context first - they are going to be recreated. 
		ReleaseCOM(d3dDevice);
		ReleaseCOM(d3dImmediateContext);

		//Set d3dDriverType to software driver type (REFERENCE)
		//Essentially, this creates a D3D11 software driver - it
		//will ensure that our demo application will work on
		//hardware without DX11 supported kit - it is, however,
		//very slow. ONLY AVAILABLE TO THOSE WITH THE SDK INSTALLED - 
		//For game studios I would expect them to have the latest Dx
		//SDK installed, but you never know. So if it doesnt work...
		//that could be your issue. 

		//Setting the d3dDriverType variable here
		//will ensure that, for example, on a resize,
		//the device and context will be created correctly again. 
		d3dDriverType = D3D_DRIVER_TYPE_REFERENCE;

		//Recreate the device and context. 
		HRESULT hr = D3D11CreateDevice(
		NULL,                 //Default adaptor
		d3dDriverType,
		NULL,
		createDeviceFlags,
		NULL, NULL,            //Default feature levels array
		D3D11_SDK_VERSION,
		&d3dDevice,
		&featureLevel, 
		&d3dImmediateContext);
		
		if (FAILED(hr))
		{
			MessageBox(0,L"D3D11CreateDevice Failed (For SOFTWARE Driver Type)",0,0);
			exit(31);
		}
	}

	//Store the new backbuffer height/width - will be matching the client width and height.
	backBufferWidth = sharedApplication->ReturnClientWidth();
	backBufferHeight = sharedApplication->ReturnClientHeight();

	//Check for 4xMSAA quality support for our back buffer. All Dx11 cards
	//will support 4x MSAA for all render targets, but we need to know
	//the quality level supported. 
	HR(d3dDevice->CheckMultisampleQualityLevels(
		BACKBUFFER_FORMAT, 4, &msaaQuality));
	assert (msaaQuality > 0); //If == 0, error!

	//Decrement msaaQuality by 1. This then gives the value that would
	//be expected by textures
	msaaQuality--;

	//Swap Chain
	//Fill out the DXGI_SWAP_CHAIN struct to describe out swap chain
	DXGI_SWAP_CHAIN_DESC sc;
	sc.BufferDesc.Width = backBufferWidth;
	sc.BufferDesc.Height = backBufferHeight;
	
	//Zero out -> DXGI will work out the refresh rate autmatically for us.
	//(My screen at home - 60,000 / 1001
	sc.BufferDesc.RefreshRate.Numerator = 0;	
	sc.BufferDesc.RefreshRate.Denominator = 0;

	sc.BufferDesc.Format =  BACKBUFFER_FORMAT;
	sc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	//No msaa
	if (!msaaEnabled)
	{
		sc.SampleDesc.Count = 1;
		sc.SampleDesc.Quality = 0;
	}
	else
	{
		sc.SampleDesc.Count = 4;
		sc.SampleDesc.Quality = msaaQuality;
	}

	sc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sc.BufferCount = 1;
	sc.OutputWindow = mainWnd;
	sc.Windowed = true;
	sc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	sc.Flags = 0;

	//In order to correctly create the swap chain, we need to obtain the 
	//IDXGIFactory that was used to create the device. Failing to do so results
	//in an error. 
	//Thus, some strange C++ code is needed to obtain the reference. 
	IDXGIDevice* dxgiDevice = NULL;
	HR(d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));

	IDXGIAdapter* dgxiAdapter = NULL;
	HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dgxiAdapter));

	IDXGIFactory* dxgiFactory = NULL;
	HR(dgxiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

	HR(dxgiFactory->CreateSwapChain(d3dDevice, &sc, &swapChain));

	//Code which will turn off the ALT+ENTER functionality that will toggle
	//the render window between Fullscreen and Windowed mode. We will NOT keep this
	//in this demo program but I shall keep the code here (commented)
	//just incase.
	/*dxgiFactory->MakeWindowAssociation(mainWnd, DXGI_MWA_NO_WINDOW_CHANGES);*/
	
	//Clean up afterourselves - ReleaseCOM is a macro found in D3dUtil.
	ReleaseCOM(dxgiDevice);
	ReleaseCOM(dgxiAdapter);
	ReleaseCOM(dxgiFactory);

	//The remaining steps for D3D creation also need to be done 
	//when ever a window is resized - thus, to save code duplication
	//we will call OnResize(). 
	OnResize();
}

void GraphicsManager::OnResize()
{
	//Ensure that the device, context and swap chain exits. 
	assert(d3dImmediateContext);
	assert(d3dDevice);
	assert(swapChain);

	//Obtain new client width/height - again, we are sizing things to the same
	//size as the client area. (if you used SSAA, then these lines of code
	//certainly need changing.) - this is pointless when OnResize() is called
	//from inside the Init function - though its VITAL as the OnResize() will be
	//called everytime the user changes the size of the window. (Or when they
	//enter full screen mode - I *think* the buffers will be automatically
	//resized to match the device (monitor) resolution).
	backBufferWidth = sharedApplication->ReturnClientWidth();
	backBufferHeight = sharedApplication->ReturnClientHeight();

	//Work out the MSAA quality for the depth/stencil buffer
	//data format.
	UINT msaaQualityDepthStencil = 0;
	HR(d3dDevice->CheckMultisampleQualityLevels(
		DXGI_FORMAT_R24G8_TYPELESS, 4, &msaaQualityDepthStencil));
	assert (msaaQualityDepthStencil > 0); //If == 0, error!

	//Also decrement - as we usually do.
	msaaQualityDepthStencil--;

	//Release old views and the old depth/stencil buffer.
	ReleaseCOM(backBufferRenderTargetView);
	ReleaseCOM(depthStencilView);
	ReleaseCOM(depthStencilSRV);

	//Resize the swap chain and recreate the render target views. 
	HR(swapChain->ResizeBuffers(1, backBufferWidth, backBufferHeight, BACKBUFFER_FORMAT, 0));
	ID3D11Texture2D* backBuffer;
	HR(swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
	D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
	rtvDesc.Format = BACKBUFFER_FORMAT;
	if (!msaaEnabled)
		rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
	else
		rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
	rtvDesc.Texture2D.MipSlice = 0;
	HR(d3dDevice->CreateRenderTargetView(backBuffer, &rtvDesc, &backBufferRenderTargetView));
	ReleaseCOM(backBuffer);

	//Create depth/stencil buffer and view. 
	D3D11_TEXTURE2D_DESC dsDesc;

	dsDesc.Width = backBufferWidth;
	dsDesc.Height = backBufferHeight;
	dsDesc.MipLevels = 1;
	dsDesc.ArraySize = 1;
	//Typeless so that we can create a SRV and DSV.
	//DSV = DXGI_FORMAT_D24_UNORM_S8_UINT;
	dsDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;

	//No MSAA
	if (!msaaEnabled)
	{
		dsDesc.SampleDesc.Count = 1;
		dsDesc.SampleDesc.Quality = 0;
	}
	//MSAA
	else
	{
		dsDesc.SampleDesc.Count = 4;
		dsDesc.SampleDesc.Quality = msaaQualityDepthStencil;
	}

	dsDesc.Usage = D3D11_USAGE_DEFAULT;
	//Also create a SRV to the depth buffer - we will render
	//it out for debug purposes (to ensure that the Z pre pass stage works)
	dsDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
	dsDesc.CPUAccessFlags = NULL;
	dsDesc.MiscFlags = NULL;

	//Create depth buffer texture.
	ID3D11Texture2D* depthStencilBuffer;
	HR(d3dDevice->CreateTexture2D(&dsDesc, NULL, &depthStencilBuffer));

	//Create DSV - Note we need to specify the format here.
	D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
	ZeroMemory(&dsvDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
	dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	if (!msaaEnabled)
		dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	else
		dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
	dsvDesc.Flags = 0; //NOT read only.
	HR(d3dDevice->CreateDepthStencilView(depthStencilBuffer, &dsvDesc, &depthStencilView));

	//Create SRV
	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
	if (!msaaEnabled)
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	else
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
	srvDesc.Texture2D.MipLevels = 1;
	srvDesc.Texture2D.MostDetailedMip = 0;
	HR(d3dDevice->CreateShaderResourceView(depthStencilBuffer, &srvDesc, &depthStencilSRV));

	//Bind the render target view and depth/stencil view to the pipeline
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);

	//Release depthStencilBuffer texture.
	ReleaseCOM(depthStencilBuffer);

	//Set the viewport transform (Default to the entire screen)
	screenViewport.TopLeftX = 0;
	screenViewport.TopLeftY = 0;
	screenViewport.Width = static_cast<float>(backBufferWidth);
	screenViewport.Height = static_cast<float>(backBufferHeight);
	screenViewport.MinDepth = 0.0f;
	screenViewport.MaxDepth = 1.0f;

	//Apply viewport to the context
	d3dImmediateContext->RSSetViewports(1, &screenViewport);

	//set aspect ratio
	backBufferAspect = static_cast<float> (backBufferWidth) / (backBufferHeight);

	//Resize (Or create) the Light List Index Buffer(LLIB) and LightListStartEndBuffer (LLSEB)
	//used within the tile based renderer. Both of these depend on the screen size
	//and thus need to be destroyed and recreated everytime a Resize event
	//occurs. 
	CreateLLIBAndLLSEB();

	//Resize (or create) the Max Tile Z Buffer. Same idea as above, per a per tile 
	//list of max depth values. Used internally in the Light Culling Stage Compute
	//Shader. 
	CreateMaxTileZBuffer();

	//Update effects that need this newly updated data - Not when this function
	//is called when we are initing D3D.
	if (sharedShaderManager)
		sharedShaderManager->OnResize(backBufferWidth, backBufferHeight);
}

//
// General D3D functions - eg clearing buffers and presenting.
//

void GraphicsManager::BindAndClearBackBuffer()
{
	//Clear backbuffer (black) - NOT THE DEPTH STENCIL VIEW, however.
	d3dImmediateContext->ClearRenderTargetView(backBufferRenderTargetView, 
		reinterpret_cast<const float*>(&Colors::Black));

	//Rebind backbuffer - also bind the depth stencil view again. We can call this function
	//to set us up for forward rendering too (Though NOT multiple times as this function
	//clears the backbuffer - so if you do the gbuffer pass, call this function, do the
	//lighting pass and then recall this function, you have just lost all your hard work)
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);

	//Also bind the standard viewport - we are rendering to the full screen.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);
}

void GraphicsManager::BindAndClearBackBufferColour(const float* col)
{
	//Clearbackbuffer - NOT THE DEPTH STENCIL VIEW, however.
	d3dImmediateContext->ClearRenderTargetView(backBufferRenderTargetView, col);

	//Bind backbuffer. 
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);

	//Also bind the standard viewport - we are rendering to the full screen.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);
}

void GraphicsManager::BindBackBuffer()
{
	//Bind backbuffer. 
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);

	//Also bind the standard viewport - we are rendering to the full screen.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);
}

void GraphicsManager::ClearDepthStencilView(float depthValue, UINT8 stencilValue)
{
	//Clear depth stencil view.
	d3dImmediateContext->ClearDepthStencilView(depthStencilView, 
		D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, depthValue, stencilValue);
}

void GraphicsManager::Present(bool vysnc)
{
	//Flip the backbuffer and primarybuffer.
	if (!vysnc)
	{
		HR(swapChain->Present(0, 0));
	}
	else
	{
		HR(swapChain->Present(1, 0));
	}
}

//
// MSAA Functions
//

void GraphicsManager::Enable4xMSAA()
{
	if (!msaaEnabled)
	{
		msaaEnabled = true;

		//Check for 4xMSAA quality support for our back buffer. All Dx11 cards
		//will support 4x MSAA for all render targets, but we need to know
		//the quality level supported. 
		HR(d3dDevice->CheckMultisampleQualityLevels(
			DXGI_FORMAT_R8G8B8A8_UNORM, 4, &msaaQuality));
		assert (msaaQuality > 0);

		//Decrement msaaQuality - we would do it anyway.
		msaaQuality--;

		//Are we currently in FS mode?
		BOOL fsState;
		swapChain->GetFullscreenState(&fsState, 0);

		//Release our swapchain
		ReleaseCOM(swapChain);

		//Obtain clinet width and height
		backBufferWidth = sharedApplication->ReturnClientWidth();
		backBufferHeight = sharedApplication->ReturnClientHeight();

		//Swap Chain
		//Fill out the DXGI_SWAP_CHAIN struct to describe out swap chain
		DXGI_SWAP_CHAIN_DESC sc;
		sc.BufferDesc.Width = backBufferWidth;
		sc.BufferDesc.Height = backBufferHeight;
		sc.BufferDesc.RefreshRate.Numerator = 0;
		sc.BufferDesc.RefreshRate.Denominator = 0;
		sc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		sc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

		//using 4x msaa
		if (msaaEnabled)
		{
			sc.SampleDesc.Count = 4;
			sc.SampleDesc.Quality = msaaQuality;
		}
		//No msaa
		else
		{
			sc.SampleDesc.Count = 1;
			sc.SampleDesc.Quality = 0;
		}

		sc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sc.BufferCount = 1;
		sc.OutputWindow = sharedApplication->MainWindowHandle();
		sc.Windowed = !fsState;
		sc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
		sc.Flags = NULL;

		//In order to correctly create the swap chain, we need to obtain the 
		//IDXGIFactory that was used to create the device. Failing to do so results
		//in an error. 
		//Thus, some strange C++ code is needed to obtain the reference. 
		IDXGIDevice* dxgiDevice = NULL;
		HR(d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));

		IDXGIAdapter* dgxiAdapter = NULL;
		HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dgxiAdapter));

		IDXGIFactory* dxgiFactory = NULL;
		HR(dgxiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

		HR(dxgiFactory->CreateSwapChain(d3dDevice, &sc, &swapChain));

		//Code which will turn off the ALT+ENTER functionality that will toggle
		//the render window between Fullscreen and Windowed mode. We will keep this
		//available in this demo program but I shall keep the code here (commented)
		//just incase.
		/*dxgiFactory->MakeWindowAssociation(mainWnd, DXGI_MWA_NO_WINDOW_CHANGES);*/
	
		//Clean up afterourselves - ReleaseCOM is a macro found in D3dUtil.
		ReleaseCOM(dxgiDevice);
		ReleaseCOM(dgxiAdapter);
		ReleaseCOM(dxgiFactory);

		//The remaining steps for D3D creation also need to be done 
		//when ever a window is resized - thus, to save code duplication
		//we will call OnResize(). 
		OnResize();
	}
}

void GraphicsManager::Disable4xMSAA()
{
	if (msaaEnabled)
	{
		msaaEnabled = false;

		//Check for 4xMSAA quality support for our back buffer. All Dx11 cards
		//will support 4x MSAA for all render targets, but we need to know
		//the quality level supported. 
		HR(d3dDevice->CheckMultisampleQualityLevels(
			DXGI_FORMAT_R8G8B8A8_UNORM, 4, &msaaQuality));
		assert (msaaQuality > 0);

		//Decrement msaaQuality - we would do it anyway.
		msaaQuality--;

		//Are we currently in FS mode?
		BOOL fsState;
		swapChain->GetFullscreenState(&fsState, 0);

		//Release our swapchain
		ReleaseCOM(swapChain);

		//Obtain clinet width and height
		backBufferWidth = sharedApplication->ReturnClientWidth();
		backBufferHeight = sharedApplication->ReturnClientHeight();

		//Swap Chain
		//Fill out the DXGI_SWAP_CHAIN struct to describe out swap chain
		DXGI_SWAP_CHAIN_DESC sc;
		sc.BufferDesc.Width = backBufferWidth;
		sc.BufferDesc.Height = backBufferHeight;
		sc.BufferDesc.RefreshRate.Numerator = 0;
		sc.BufferDesc.RefreshRate.Denominator = 0;
		sc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		sc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

		//using 4x msaa
		if (msaaEnabled)
		{
			sc.SampleDesc.Count = 4;
			sc.SampleDesc.Quality = msaaQuality;
		}
		//No msaa
		else
		{
			sc.SampleDesc.Count = 1;
			sc.SampleDesc.Quality = 0;
		}

		sc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sc.BufferCount = 1;
		sc.OutputWindow = sharedApplication->MainWindowHandle();
		sc.Windowed = !fsState;
		sc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
		sc.Flags = NULL;

		//In order to correctly create the swap chain, we need to obtain the 
		//IDXGIFactory that was used to create the device. Failing to do so results
		//in an error. 
		//Thus, some strange C++ code is needed to obtain the reference. 
		IDXGIDevice* dxgiDevice = NULL;
		HR(d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));

		IDXGIAdapter* dgxiAdapter = NULL;
		HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dgxiAdapter));

		IDXGIFactory* dxgiFactory = NULL;
		HR(dgxiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

		HR(dxgiFactory->CreateSwapChain(d3dDevice, &sc, &swapChain));

		//Code which will turn off the ALT+ENTER functionality that will toggle
		//the render window between Fullscreen and Windowed mode. We will keep this
		//available in this demo program but I shall keep the code here (commented)
		//just incase.
		/*dxgiFactory->MakeWindowAssociation(mainWnd, DXGI_MWA_NO_WINDOW_CHANGES);*/
	
		//Clean up afterourselves - ReleaseCOM is a macro found in D3dUtil.
		ReleaseCOM(dxgiDevice);
		ReleaseCOM(dgxiAdapter);
		ReleaseCOM(dxgiFactory);

		//The remaining steps for D3D creation also need to be done 
		//when ever a window is resized - thus, to save code duplication
		//we will call OnResize(). 
		OnResize();
	}
}

//
// Functionality for the tile based forward renderer
//
//
// Stage 1 - Z Pre Pass	
//

void GraphicsManager::BeginZPrePassStage()
{
	//Restore OM Depth/Stencil state to default - you can still use your own
	//if you so choose (eg, you clear the depth buffer to 0.0f rather than
	//1.0f)
	d3dImmediateContext->OMSetDepthStencilState(NULL, 0);

	//Set standard full screen viewport.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);

	//Bind the standard depth buffer - No Render Targets.
	d3dImmediateContext->OMSetRenderTargets(0, NULL, depthStencilView);
}

//
// Stage 2 - Light Culling Stage	
//

void GraphicsManager::SetSceneLights(TileBasedLight* lightArray, unsigned count, 
	bool shouldCreateVisBuffers)
{
	//Create the Light List Buffer. This is the buffer which contains all of 
	//our lights (Point and Spot).
	//
	//Release old buffer and SRV
	ReleaseCOM(lightListBuffer);
	ReleaseCOM(lightListBufferSRV);

	//Store the number of lights set.
	lightCount = count;

	//Fillout buffer description
	D3D11_BUFFER_DESC bd;
	//Input to CS and effects
	bd.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	//Total size of buffer to be allocated.
	bd.ByteWidth = sizeof(TileBasedLight) * count;
	//We allow the user to map to the resource to update the light sources - this
	//assumes that we wont be creating/destroying lights - just moving them
	//or changing colours. In our demo, we dont use this - but for games case, I may
	//need to make use of this functionality.
	//
	//Instead, we will just recreate the buffer each time we want to change the scene
	//lights (Our Demo Scene will contain static (They are still "Dynamic lights" however) lights)
	bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 
	//Structure buffer - we use our custom data structure
	bd.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	bd.StructureByteStride = sizeof(TileBasedLight);
	//Dynamic buffer - Can be updated by the CPU via the mapping API.
	bd.Usage = D3D11_USAGE_DYNAMIC;

	//Fillout subresource data structure - our initial data to fill the above
	//buffer.
	D3D11_SUBRESOURCE_DATA sd;
	sd.pSysMem = &lightArray[0];

	if (lightCount > 0)
	{
		//Create the buffer in GPU memory
		HR(d3dDevice->CreateBuffer(&bd, &sd, &lightListBuffer));

		//Create Shader resource View
		D3D11_SHADER_RESOURCE_VIEW_DESC srd;
		//Custom format
		srd.Format = DXGI_FORMAT_UNKNOWN;
		srd.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
		srd.Buffer.FirstElement = 0;
		srd.Buffer.ElementOffset = 0;
		//Note, we pick either NumElements or ElementWidth - they are in "union" within the
		//data structure. Thanks to MJP for clearing it up in one of my threads:
		//www.gamedev.net/topic/648794-creating-a-srv-to-a-id3d11buffer-resource/
		srd.Buffer.NumElements = count;

		//Init SRV
		HR(d3dDevice->CreateShaderResourceView(lightListBuffer, &srd, &lightListBufferSRV));

		//Upload light list buffer in our light culling effect. Note sstrictly 'uploading', as
		//the light list buffer is already in GPU memory. Essentially, just telling the effect
		//where the light list buffer memroy is located. 
		tileCullCSEffect->SetLightListBuffer(lightListBufferSRV);
		//Update light count in effect
		tileCullCSEffect->SetLightData(lightCount);

		//Ask our effects to update the llb (probably not used)
		sharedShaderManager->OnReallocOfLLB(lightListBufferSRV);

		//Create the data required to visualise the lights
		//Release old instanced data
		ReleaseCOM(lightsInstancedBuffer);
		//Recreate instanced data.
		if (shouldCreateVisBuffers)
			CreateLightVisInstanceBuffer(lightArray);
	}
}

void GraphicsManager::UpdateSceneLights(TileBasedLight* newLightArray, bool shouldCreateVisBuffers)
{
	//Map to the LLB in such a way that a newly allocated buffer (same size) is
	//returned. This prevents stalls as the old data can still be used
	//if any rendering is being done).
	D3D11_MAPPED_SUBRESOURCE mappedData;
	HR(d3dImmediateContext->Map(lightListBuffer, 0, D3D11_MAP_WRITE_DISCARD,
		0, &mappedData));

	//Update data
	TileBasedLight* newData = reinterpret_cast<TileBasedLight*>(mappedData.pData);
	for (unsigned i = 0; i < lightCount; i++)
		newData[i] = newLightArray[i];

	//Unmap
	d3dImmediateContext->Unmap(lightListBuffer, 0);

	//Create the data required to visualise the lights
	//Release old instanced data
	ReleaseCOM(lightsInstancedBuffer);
	//Recreate instanced data.
	if (shouldCreateVisBuffers)
		CreateLightVisInstanceBuffer(newLightArray);
}

void GraphicsManager::CreateLLIBAndLLSEB()
{
	//NOTE: sizeof(UINT) == 32(bits). Thus, use 32 bit data formats. Our approach
	//is a little memory inefficient at times (Eg the LLSEB), but this solution is
	//not going to be perfect I'm afraid.

	//Release old data - all will be recreated. 
	ReleaseCOM(lightListIndexBuffer);
	ReleaseCOM(lightListStartEndBuffer);
	ReleaseCOM(lightListIndexBufferUAV);
	ReleaseCOM(lightListStartEndBufferUAV);
	ReleaseCOM(lightListIndexBufferSRV);
	ReleaseCOM(lightListStartEndBufferSRV);
	//Release T views - note that we do NOT store the buffers (Release them 
	//once the views have been created) because we do not need to. 
	ReleaseCOM(lightListIndexBufferTSRV);
	ReleaseCOM(lightListIndexBufferTUAV);
	ReleaseCOM(lightListStartEndBufferTSRV);
	ReleaseCOM(lightListStartEndBufferTUAV);


	//Workout how many tiles are required at the selected resolution to
	//cover the screen
	//
	float tilesX = 0.0f;
	float tilesY = 0.0f;
	ObtainTilesCount(tilesX, tilesY);

	//Workout total tiles for the screen.
	UINT totalTiles = (UINT)tilesX * (UINT)tilesY;

	//Create LLIB  
	D3D11_BUFFER_DESC llibBD;
	llibBD.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	llibBD.ByteWidth = sizeof(UINT) * MAX_LIGHTS_PER_TILE * totalTiles;
	llibBD.CPUAccessFlags = 0;
	llibBD.MiscFlags = 0;
	llibBD.StructureByteStride = 0;
	//GPU Read-Write access.
	llibBD.Usage = D3D11_USAGE_DEFAULT;
	//Create buffer - no initial data required. 
	HR(d3dDevice->CreateBuffer(&llibBD, 0, &lightListIndexBuffer));

	//Create LLSEB
	D3D11_BUFFER_DESC llsebBD;
	llsebBD.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	llsebBD.ByteWidth = sizeof(UINT) * totalTiles * 2; //2 valus per tile (start and end)
	llsebBD.CPUAccessFlags = 0;
	llsebBD.MiscFlags = 0;
	llsebBD.StructureByteStride = 0;
	llsebBD.Usage = D3D11_USAGE_DEFAULT;
	//Create buffer - no initial data again.
	HR(d3dDevice->CreateBuffer(&llsebBD, 0, &lightListStartEndBuffer));

	//Create LLIB Resource Views
	//SRV
	D3D11_SHADER_RESOURCE_VIEW_DESC llibSRVDesc;
	//32 bit unsigned integer format. Each entry in our 'array'
	//represents one index in to the LLB
	llibSRVDesc.Format = DXGI_FORMAT_R32_UINT;
	llibSRVDesc.Buffer.FirstElement = 0;
	llibSRVDesc.Buffer.ElementOffset = 0;
	llibSRVDesc.Buffer.NumElements = MAX_LIGHTS_PER_TILE * totalTiles;
	llibSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
	HR(d3dDevice->CreateShaderResourceView(lightListIndexBuffer, &llibSRVDesc, 
		&lightListIndexBufferSRV));
	//UAV
	D3D11_UNORDERED_ACCESS_VIEW_DESC llibUAVDesc;
	llibUAVDesc.Format = DXGI_FORMAT_R32_UINT;
	llibUAVDesc.Buffer.FirstElement = 0;
	llibUAVDesc.Buffer.Flags = 0;
	llibUAVDesc.Buffer.NumElements = MAX_LIGHTS_PER_TILE * totalTiles;
	llibUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
	HR(d3dDevice->CreateUnorderedAccessView(lightListIndexBuffer, &llibUAVDesc, 
		&lightListIndexBufferUAV));

	//Create LLSEB Views.
	//SRV
	D3D11_SHADER_RESOURCE_VIEW_DESC llsebSRVDesc;
	//2 32 bit UINTs per entry (xy)
	llsebSRVDesc.Format = DXGI_FORMAT_R32G32_UINT;
	llsebSRVDesc.Buffer.FirstElement = 0;
	llsebSRVDesc.Buffer.ElementOffset = 0;
	llsebSRVDesc.Buffer.NumElements = totalTiles;
	llsebSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
	HR(d3dDevice->CreateShaderResourceView(lightListStartEndBuffer, &llsebSRVDesc, 
		&lightListStartEndBufferSRV));
	//UAV
	D3D11_UNORDERED_ACCESS_VIEW_DESC llsebUAVDesc;
	llsebUAVDesc.Format = DXGI_FORMAT_R32G32_UINT;
	llsebUAVDesc.Buffer.FirstElement = 0;
	llsebUAVDesc.Buffer.Flags = 0;
	llsebUAVDesc.Buffer.NumElements = totalTiles;
	llsebUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
	HR(d3dDevice->CreateUnorderedAccessView(lightListStartEndBuffer, &llsebUAVDesc, 
		&lightListStartEndBufferUAV));

	//Modified: 24/10/13 - Create transparant views. We dont store the buffers (Release them
	//at the end of this function). Note that these buffers are identical to the opaque
	//counterparts - thus, create the buffers with the same buffer description (and indeed, the
	//UAV and SRV descriptions). Note that this will allocate new memory for these buffers. 
	//
	//Create buffers. 
	ID3D11Buffer* llibT;
	ID3D11Buffer* llsebT;
	HR(d3dDevice->CreateBuffer(&llibBD, 0, &llibT));
	HR(d3dDevice->CreateBuffer(&llsebBD, 0, &llsebT));
	//Create viws to llibT.
	HR(d3dDevice->CreateShaderResourceView(llibT, &llibSRVDesc, &lightListIndexBufferTSRV));
	HR(d3dDevice->CreateUnorderedAccessView(llibT, &llibUAVDesc, &lightListIndexBufferTUAV));
	//Create views to llsebT
	HR(d3dDevice->CreateShaderResourceView(llsebT, &llsebSRVDesc, &lightListStartEndBufferTSRV));
	HR(d3dDevice->CreateUnorderedAccessView(llsebT, &llsebUAVDesc, &lightListStartEndBufferTUAV));

	//Release buffers to avoid memory leakes - doesnt dealloc memory as it uses a refernece
	//counting system. 
	ReleaseCOM(llibT);
	ReleaseCOM(llsebT);
}

void GraphicsManager::CreateMaxTileZBuffer()
{
	//Release old data
	ReleaseCOM(maxTileZBuffer);
	ReleaseCOM(maxTileZBufferUAV);

	//Workout how many tiles are required at the selected resolution to
	//cover the screen
	//
	float tilesX = 0.0f;
	float tilesY = 0.0f;
	ObtainTilesCount(tilesX, tilesY);

	//Workout total tiles for the screen.
	UINT totalTiles = (UINT)tilesX * (UINT)tilesY;

	//(Re)create the buffer.
	D3D11_BUFFER_DESC bd;
	bd.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	//One floating point value (32 bit) per tile.
	bd.ByteWidth = sizeof(float) * totalTiles;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	//Gpu read-write
	bd.Usage = D3D11_USAGE_DEFAULT;
	HR(d3dDevice->CreateBuffer(&bd, NULL, &maxTileZBuffer));

	//(Re)create the view (UAV/SRV)
	//UAV
	D3D11_UNORDERED_ACCESS_VIEW_DESC ud;
	ud.Format = DXGI_FORMAT_R32_FLOAT;
	ud.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
	ud.Buffer.FirstElement = 0;
	ud.Buffer.Flags = 0;
	ud.Buffer.NumElements = totalTiles;
	HR(d3dDevice->CreateUnorderedAccessView(maxTileZBuffer, &ud, &maxTileZBufferUAV));
}

void GraphicsManager::PreformLightCull(VirtualCamera* mainCam)
{
	//Check to ensure that the light list buffer has been created - if NULL, then
	//there is no light list buffer. Print error, and enter infinine loop
	//to prevent things from going wrong. 
	if (!lightListBuffer)
	{
		OutputDebugStringW(L"Graphics Manager Error: Light List Buffer is NULL. "
						   L"Can not preform light culling\n");
		while(1){}
	}

	//We have to unbind the depthstencil buffer as it is input to the Compute
	//Shader - we can not have things bound as output and input at the same
	//time. 
	ID3D11RenderTargetView* rtvArray[] = {backBufferRenderTargetView};
	d3dImmediateContext->OMSetRenderTargets(1, rtvArray, NULL);

	//Workout how many tiles are required at the selected resolution to
	//cover the screen - used in the compute shaders Dispatch() call. Each dispatch
	//will have a thread group size of 32*32 threads. Thus, when we know how many tiles
	//cover the screen, we can dispatch enough threads to cover the entire screen. Note, 
	//that writes/reads out of bounds will return 0 or not preform a write - so its safe
	//to dispatch too many threads (Better than dispatching too few). 
	float tilesX = 0.0f;
	float tilesY = 0.0f;
	ObtainTilesCount(tilesX, tilesY);

	//Set TileForwardLightCullCSFX variables.
	XMVECTOR det = XMMatrixDeterminant(mainCam->GetProjection());
	XMMATRIX invProj = XMMatrixInverse(&det, mainCam->GetProjection());

	tileCullCSEffect->SetPerFrameCBuffer(invProj, mainCam->GetView());
	tileCullCSEffect->SetOnResizeCBuffer( (float)backBufferWidth, (float)backBufferHeight );
	tileCullCSEffect->SetInputDepthTexture(depthStencilSRV, msaaEnabled);
	tileCullCSEffect->SetLightListIndexBufferOutput(lightListIndexBufferUAV);
	tileCullCSEffect->SetLightListStartEndBufferOutput(lightListStartEndBufferUAV);
	tileCullCSEffect->SetMaxZTileBuffer(maxTileZBufferUAV);
	//Set Transparancy tile buffers. 
	tileCullCSEffect->SetLightListIndexBufferTransparantOutput(lightListIndexBufferTUAV);
	tileCullCSEffect->SetLightListStartEndBufferTransparantOutput(lightListStartEndBufferTUAV);

	//Set technique. 
	if (msaaEnabled)
		tileCullCSEffect->SetActiveTechniqueByName("LightCullTechniqueMSAA");
	else
		tileCullCSEffect->SetActiveTechniqueByName("LightCullTechnique");

	//Dispatch the TileForwardLightCull Compute Shader. (tileCullCSEffect). One thread group
	//per tile. 
	for (unsigned p = 0; p < tileCullCSEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		tileCullCSEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->Dispatch((UINT)tilesX, (UINT)tilesY, 1);
	}

	//Unbind resources (UAV/SRV)
	ID3D11UnorderedAccessView* uavNULL[] = {NULL, NULL, NULL, NULL, NULL};
	ID3D11ShaderResourceView* srvNULL[] = {NULL, NULL, NULL};
	d3dImmediateContext->CSSetUnorderedAccessViews(0, 5, uavNULL, 0);
	d3dImmediateContext->CSSetShaderResources(0, 3, srvNULL);

	//rebind backbuffer and depth stencil view
	d3dImmediateContext->OMSetRenderTargets(1, rtvArray, depthStencilView);
}

void GraphicsManager::ObtainTilesCount(float& x, float& y)
{
	//Workout how many tiles are required at the selected resolution to
	//cover the screen - used in the compute shaders Dispatch() call. Each dispatch
	//will have a thread group size of n*n threads*. Thus, when we know how many tiles
	//cover the screen, we can dispatch enough threads to cover the entire screen. Note, 
	//that writes/reads out of bounds will return 0 or not preform a write - so its safe
	//to dispatch too many threads (Better than dispatching too few). 
	//
	//Also has use when creating our LLIB and LLSEB.
	//
	//ceilf() rounds up.
	//
	//*n == TILE_PIXEL_RESOLUTION
	x = ceilf(((float)sharedApplication->ReturnClientWidth() / (float)TILE_PIXEL_RESOLUTION));
	y = ceilf(((float)sharedApplication->ReturnClientHeight() / (float)TILE_PIXEL_RESOLUTION));
}

//
// Stage 3 - Shading
//

void GraphicsManager::BeginOpaqueShadingStage()
{
	//Set new Depth/Stencil State == depth test
	d3dImmediateContext->OMSetDepthStencilState(RenderStates::equalsDepthTestDSS, 0);

	//Enable colour writies - return the blend state to 
	//its default
	d3dImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff);

	//Set standard full screen viewport.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);

	//Bind RTV again - and the standard depth buffer. 
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);
}

void GraphicsManager::BeginTransparantShadingStage()
{
	//Set new Depth/Stencil state. Depth test is < and no depth writes - transparant object
	//still need the depth test!
	d3dImmediateContext->OMSetDepthStencilState(RenderStates::lessThanNoDepthWritesDSS, 0);

	//Enable colour writies - Enable my default alpha blending state.
	d3dImmediateContext->OMSetBlendState(RenderStates::transparentBS, NULL, 0xffffffff);

	//Set standard full screen viewport.
	d3dImmediateContext->RSSetViewports(1, &screenViewport);

	//Bind RTV again - and the standard depth buffer. 
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);
}

//
//Tile Based Forward Rendering Debug Functionality
//

void GraphicsManager::CreateFullScreenQuad()
{
	//Buffer description
	D3D11_BUFFER_DESC bd;
	//Subresource data structure.
	D3D11_SUBRESOURCE_DATA sd;

	//Create geometry generator instance. Has functionality
	//to create a full screen quad. 
	GeometryGenerator geoGen;
	//MeshData will be filled with our vertex and index data 
	//for our quad. We can loop though and extract data
	GeometryGenerator::MeshData data;
	//Create the quad - filling data structure from above.
	geoGen.CreateFullscreenQuad(data);

	//A vector to hold our vertex data. Will be the SUBRESOURCE_DATA for the
	//vertex buffer - ie, the initial data (it will be an immutable
	//buffer (not changed after initlization)
	std::vector<TexturedFullScreenQuadFX::PosTex>vert(data.Vertices.size());

	//Loop through data and extract vertex data
	for (unsigned i = 0; i < data.Vertices.size(); i++)
	{
		vert[i].Pos = data.Vertices[i].Position;
		vert[i].Tex = data.Vertices[i].TexC;
	}

	//Fillout buffer description and subresource structures.
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	//Total size of the vertex buffer.
	bd.ByteWidth = sizeof(TexturedFullScreenQuadFX::PosTex) * data.Vertices.size();
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0; //Not a structured buffer
	bd.Usage = D3D11_USAGE_IMMUTABLE;

	//Pointer to the start of our extract vertex data
	sd.pSysMem = &vert[0];

	//Create the Vertex buffer in video memory
	HR(d3dDevice->CreateBuffer(&bd, &sd, &quadVB));

	//Create the index buffer - we will reuse the buffer description and
	//subresource struct - jusyt changing what we need to.
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.ByteWidth = sizeof(UINT) * data.Indices.size(); // R32_UINT.

	sd.pSysMem = &data.Indices[0];

	//Create index buffer.
	HR(d3dDevice->CreateBuffer(&bd, &sd, &quadIB));
}

void GraphicsManager::DrawZPrePassFilledDepthBuffer()
{
	//Note: Our depth buffer can be created with MSAA enabled - You must
	//handle these texture(2D) objects differently. Inside the shader, you
	//create a Texture2DMS<float, 4> object rather than a Texture2D object. 
	//
	//Unbding depth stencil view.
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, NULL);

	//Set active technique.
	if (!msaaEnabled)
		quadEffect->SetActiveTechniqueByName("R24_UNORM_X8_TYPELESS");
	else
		quadEffect->SetActiveTechniqueByName("R24_UNORM_X8_TYPELESS_MSAA");

	//Work out stide - essentially, how large is our vertex structure (per vertex)
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	//Offset - how far into the vertex buffer to begin reading. Almost always
	//0. But the bind buffers function requests an array (pointer)
	UINT offset = 0;

	//We are using triangle list - as usual.
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	//Set input layout. This sets up D3D so that it knows what data we are firing through
	//the pipeline (Position and Texture Coord data)
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());

	//Bind buffers.
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set effect variables - Our SRV to the depth buffer.
	if (!msaaEnabled)
		quadEffect->SetShaderResource(depthStencilSRV);
	else
		quadEffect->SetShaderResourceMSAA(depthStencilSRV);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind the Depth buffer from the shader (input).
	static ID3D11ShaderResourceView* nullSRV[1] = {NULL};
	d3dImmediateContext->PSSetShaderResources(0,1,&nullSRV[0]);

	//Rebind the DSV
	d3dImmediateContext->OMSetRenderTargets(1, &backBufferRenderTargetView, depthStencilView);
}

void GraphicsManager::DrawTileMaxZBuffer()
{
	//Set active technique. (Samples rrr, 1.0f - which is what we want
	//despite the differnt format that this technique was designed to use)
	quadEffect->SetActiveTechniqueByName("MaxTileZBuff");

	//Work out stide - essentially, how large is our vertex structure (per vertex)
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	//Offset - how far into the vertex buffer to begin reading. Almost always
	//0. But the bind buffers function requests an array (pointer)
	UINT offset = 0;

	//We are using triangle list - as usual.
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	//Set input layout. This sets up D3D so that it knows what data we are firing through
	//the pipeline (Position and Texture Coord data)
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());

	//Bind buffers.
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set effect variables - Our SRV to the depth buffer (Filled in our CS stage).
	quadEffect->SetUAVFloatBuffer(maxTileZBufferUAV);
	quadEffect->SetRTDimentions((float)backBufferWidth, (float)backBufferHeight);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind the max z buffer from the shader (input).
	static ID3D11ShaderResourceView* nullSRV[] = {NULL, NULL};
	d3dImmediateContext->PSSetShaderResources(0,2,&nullSRV[0]);
}

void GraphicsManager::DrawLightListStartEndBufferGreyscale()
{
	//Set active technique for the quad effect. 
	quadEffect->SetActiveTechniqueByName("LightListStartEndBuffer");

	//Set IA Stage of the pipeline.
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	UINT offset = 0;
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set variables for this effect.
	quadEffect->SetSRVUint2Buffer(lightListStartEndBufferSRV);
	quadEffect->SetRTDimentions((float)backBufferWidth, (float)backBufferHeight);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind resource.
	static ID3D11ShaderResourceView* nullSRV[] = {NULL, NULL};
	d3dImmediateContext->PSSetShaderResources(0,2,&nullSRV[0]);
}

void GraphicsManager::DrawLightListStartEndBufferColour()
{
	//Set active technique for the quad effect. 
	quadEffect->SetActiveTechniqueByName("LightListStartEndBufferColour");
	 
	//Set IA Stage of the pipeline. 
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	UINT offset = 0; 
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set variables for this effect.
	quadEffect->SetSRVUint2Buffer(lightListStartEndBufferSRV);
	quadEffect->SetRTDimentions((float)backBufferWidth, (float)backBufferHeight);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind resource.
	static ID3D11ShaderResourceView* nullSRV[] = {NULL, NULL};
	d3dImmediateContext->PSSetShaderResources(0,2,&nullSRV[0]);
}

void GraphicsManager::CreateLightPointVertexBuffer()
{
	//Extract vertex data
	DebugDrawLightsFX::PerVertex pt;
	pt.PosL = XMFLOAT3(0.0f, 0.0f, 0.0f);

	//Create vertex buffer.
	D3D11_BUFFER_DESC bd;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.ByteWidth = sizeof(XMFLOAT3);
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	bd.Usage = D3D11_USAGE_IMMUTABLE;
	
	D3D11_SUBRESOURCE_DATA sd;
	sd.pSysMem = &pt;

	HR(d3dDevice->CreateBuffer(&bd, &sd, &pointVB));
}

void GraphicsManager::CreateLightVisInstanceBuffer(TileBasedLight* lightArr)
{
	//One piece of instance data per light.
	std::vector<DebugDrawLightsFX::PerInstance>instData(lightCount);

	for (unsigned i = 0; i < lightCount; i++)
	{
		//Create and store world matrix.
		XMMATRIX wd = XMMatrixTranslation(lightArr[i].PositionW.x, 
			lightArr[i].PositionW.y, 
			lightArr[i].PositionW.z);
		XMStoreFloat4x4(&instData[i].WorldMatrix, wd);
		//Obtain of the light - we will use diffuse colour
		instData[i].Colour = lightArr[i].Diffuse;
	}

	//Create the buffer - Dynamic with CPU access (write) so we
	//can update it if we so choose. 
	D3D11_BUFFER_DESC bd;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.ByteWidth = sizeof(DebugDrawLightsFX::PerInstance) * lightCount;
	bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	bd.Usage = D3D11_USAGE_DYNAMIC;

	D3D11_SUBRESOURCE_DATA sd;
	sd.pSysMem = &instData[0];

	HR(d3dDevice->CreateBuffer(&bd, &sd, &lightsInstancedBuffer));
}

void GraphicsManager::DrawLights(VirtualCamera* cam)
{
	//Only render lights if instanced data exists (Ie, we have set the
	//scene lights AND indicated that we wish to create the instanced buffer
	if (lightsInstancedBuffer)
	{
		//Save blend state (for later restore)
        ID3D11BlendState* blendStateStored = NULL;
        FLOAT blendFactorStored[4];
        UINT sampleMaskStored;
        d3dImmediateContext->OMGetBlendState(&blendStateStored, blendFactorStored, 
			&sampleMaskStored);

        //Save depth state (for later restore)
        ID3D11DepthStencilState* depthStencilStateStored = NULL;
        UINT stencilRefStored;
        d3dImmediateContext->OMGetDepthStencilState( &depthStencilStateStored, 
			&stencilRefStored );

		//Disable Depth Writes, but enable depth test.
		d3dImmediateContext->OMSetDepthStencilState(RenderStates::lessThanNoDepthWritesDSS, 0);
		//Enable additive blending.
		float f[4]= {0.0f, 0.0f, 0.0f, 0.0f};
		d3dImmediateContext->OMSetBlendState(RenderStates::additiveBlendingBS, f, 0xFFFFFFFF);

		//Set effect variable - view projection.
		XMMATRIX vp = XMMatrixMultiply(cam->GetView(), cam->GetProjection());
		lightsDrawEffect->SetViewProj(vp);
		lightsDrawEffect->SetEyePos(cam->GetPosition());

		UINT stride[] = {sizeof(DebugDrawLightsFX::PerVertex), sizeof(DebugDrawLightsFX::PerInstance)};
		UINT offset[] = {0,0};
		ID3D11Buffer* vbs[] = {pointVB, lightsInstancedBuffer};

		d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
		d3dImmediateContext->IASetInputLayout(lightsDrawEffect->ReturnInputLayout());
		d3dImmediateContext->IASetVertexBuffers(0, 2, vbs, stride, offset);

		//Draw
		for (unsigned p = 0; p < lightsDrawEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
		{
			lightsDrawEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
			//Draw instnaced
			d3dImmediateContext->DrawInstanced(1, lightCount, 0, 0);
		}

		//Disable Geometry Shader Stage.
		d3dImmediateContext->GSSetShader(NULL, NULL, NULL);

		//Restore states.
        d3dImmediateContext->OMSetDepthStencilState(depthStencilStateStored, 
			stencilRefStored);
        d3dImmediateContext->OMSetBlendState(blendStateStored, blendFactorStored, 
			sampleMaskStored);
		//Get increments the reference count, so release to decrement.
        ReleaseCOM(depthStencilStateStored);
        ReleaseCOM(blendStateStored);
	}
	//Else, print a warning message.
	else
		OutputDebugStringW(L"Graphics Manager Warning : Trying to render lights without instanced data\n");
}

void GraphicsManager::DrawLightListStartEndBufferTransparantGreyscale()
{
	//Set active technique for the quad effect. 
	quadEffect->SetActiveTechniqueByName("LightListStartEndBuffer");

	//Set IA Stage of the pipeline.
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	UINT offset = 0;
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set variables for this effect.
	quadEffect->SetSRVUint2Buffer(lightListStartEndBufferTSRV);
	quadEffect->SetRTDimentions((float)backBufferWidth, (float)backBufferHeight);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind resource.
	static ID3D11ShaderResourceView* nullSRV[] = {NULL, NULL};
	d3dImmediateContext->PSSetShaderResources(0,2,&nullSRV[0]);
}

void GraphicsManager::DrawLightListStartEndBufferTransparantColour()
{
	//Set active technique for the quad effect. 
	quadEffect->SetActiveTechniqueByName("LightListStartEndBufferColour");
	 
	//Set IA Stage of the pipeline. 
	UINT stride = sizeof(TexturedFullScreenQuadFX::PosTex);
	UINT offset = 0; 
	d3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	d3dImmediateContext->IASetInputLayout(quadEffect->ReturnInputLayout());
	d3dImmediateContext->IASetVertexBuffers(0, 1, &quadVB, &stride, &offset);
	d3dImmediateContext->IASetIndexBuffer(quadIB, DXGI_FORMAT_R32_UINT, 0);

	//Set variables for this effect.
	quadEffect->SetSRVUint2Buffer(lightListStartEndBufferTSRV);
	quadEffect->SetRTDimentions((float)backBufferWidth, (float)backBufferHeight);

	//Draw
	for (unsigned p = 0; p < quadEffect->ReturnActiveTechniqueNumberOfPasses(); p++)
	{
		quadEffect->ApplyActiveTechniqueForPass(p, d3dImmediateContext);
		d3dImmediateContext->DrawIndexed(6, 0, 0);
	}

	//Unbind resource.
	static ID3D11ShaderResourceView* nullSRV[] = {NULL, NULL};
	d3dImmediateContext->PSSetShaderResources(0,2,&nullSRV[0]);
}